<?php

namespace app\agent\model\order;

use app\model\AgentSalesman;
use app\model\MobileSupplier;
use think\facade\Db;
use think\facade\Request;
use app\common\model\Export;
use app\common\model\FinanceStat;

class Mobile
{
    private $table = 'mobile_order';
    private $error = '';

    /**
     * 列表.
     */
    public function getList($params)
    {
        $where = [];
        $where[] = ['agent_id', '=', $params['agent']['id']];
        $where[] = ['status', '=', 2];
        if (!empty($params['channel_id'])) {
            $where[] = ['channel_id', '=', $params['channel_id']];
        }
        $mobile = trim($params['mobile'] ?? '');
        if ($mobile) {
            $where[] = ['mobile', 'like', '%' . $mobile . '%'];
        }
        if (!empty($params['supplier_status'])) {
            if (in_array($params['supplier_status'], [3, 4])) {
                $where[] = ['supplier_status', '=', $params['supplier_status']];
            } else {
                $where[] = ['supplier_status', 'in', [1, 2, 99]];
            }
        }
        if (!empty($params['order_type'])) {
            $where[] = ['order_type', '=', $params['order_type']];
        }
        $createdDate = $params['createdDate'] ?? [];
        if (is_array($createdDate) && !empty($createdDate[0]) && $createdDate[1]) {
            $where[] = ['created_at', 'between time', [$createdDate[0], $createdDate[1] . ' 23:59:59']];
        }
        $paginate = [
            'page' => $params['page'] ?? 1,
            'list_rows' => $params['list_rows'] ?? 10,
        ];
        $channelList = Db::name('agent_channel')
            ->field('id, name')
            ->where('agent_id', $params['agent']['id'])
            ->where('is_deleted', 0)
            ->order('name asc')
            ->select()
            ->toArray();
        $channel = array_column($channelList, 'name', 'id');

        $list = Db::name($this->table)
            ->field('id, channel_id, sub_order_id, out_order_id, mobile, amount,
            sale_price, profit, order_from, order_type, refund_status,
            status, remark, supplier_status, settle_price, created_at, finish_time, official_sn')
            ->where($where)
            ->order('id desc');

        // 导出数据字段处理
        if (!empty($params['is_export'])) {
            $list = $list->select()->toArray();
            $res = [];
            $title = ['系统订单号', '接口订单号', '渠道', '充值号码', '运营商', '充值金额', '售价', '结算价', '利润', '充值类型', '充值状态', '下单来源', '下单时间', '完成时间', '备注', '时长'];
            $statusMap = [
                3 => '充值成功',
                4 => '充值失败',
            ];
            $ispTypeMap = [
                1 => '移动',
                2 => '联通',
                3 => '电信',
                -1 => '未知',
            ];
            $orderFromMap = [
                ORDER_FROM_H5 => 'H5',
                ORDER_FROM_API => 'API',
                ORDER_FROM_BATCH_IMPORT => '批量导入',
            ];
            foreach ($list as $v) {
                $ispType = getMobileIsp($v['mobile']);
                $spend = '';
                if (in_array($v['supplier_status'], [3, 4]) && $v['finish_time']) {
                    $spend = getRemainderTime(strtotime($v['created_at']), $v['finish_time']);
                    $v['finish_time'] = date('Y-m-d H:i:s', $v['finish_time']);
                } else {
                    $v['finish_time'] = '';
                }
                $subOrderId = explode('_', $v['sub_order_id'])[0];
                $res[] = [
                    $subOrderId . "\t",
                    $v['out_order_id'] . "\t",
                    $channel[$v['channel_id']] ?? '',
                    $v['mobile'],
                    $ispTypeMap[$ispType],
                    fen2yuan($v['amount']) . '',
                    fen2yuan($v['sale_price']) . '',
                    fen2yuan($v['settle_price']) . '',
                    fen2yuan($v['profit']) . '',
                    $v['order_type'] == 1 ? '慢充' : '快充',
                    $statusMap[$v['supplier_status']] ?? '充值中',
                    $orderFromMap[$v['order_from']],
                    $v['created_at'],
                    $v['finish_time'],
                    $v['remark'],
                    $spend,
                ];
            }
            unset($list);
            $export = new Export;
            $name = '话费订单';
            return $export->downloadExcel($title, $res, $name);
        }

        $list = $list->paginate($paginate)->toArray();
        if ($list['data']) {
            foreach ($list['data'] as $k => $v) {
                $list['data'][$k]['channel_name'] = $channel[$v['channel_id']] ?? '';
                $list['data'][$k]['isp_type'] = getMobileIsp($v['mobile']);
                if (in_array($v['supplier_status'], [3, 4]) && $v['finish_time']) {
                    $list['data'][$k]['finish_time'] = date('Y-m-d H:i:s', $v['finish_time']);
                    $list['data'][$k]['spend'] = getRemainderTime(strtotime($v['created_at']),$v['finish_time']);
                } else {
                    $list['data'][$k]['finish_time'] = '';
                    $list['data'][$k]['spend'] = '';
                }
                $list['data'][$k]['sub_order_id'] = explode('_', $v['sub_order_id'])[0];
                $list['data'][$k]['out_order_id'] = str_replace('_', '', $v['out_order_id']);
            }
        }
        $list['channelList'] = $channelList;
        $list['excel_url'] = Request::domain() . '/mobile.xlsx';
        $list['is_prod'] = isProd() ? 1 : 0; // 控制代理商订单列表是否要显示 回调 按钮，测试环境才显示

        return success('操作成功', $list);
    }

    /**
     * Excel 批量导入订单.
     */
    public function batchImport($data, $agentId)
    {
        $list = [];
        $orderNum = 0;
        $orderAmount = 0;
        $map = [
            1 => 'yidong',
            2 => 'liantong',
            3 => 'dianxin',
            -1 => 'other',
        ];
        $filename = root_path() . '/data/mobileSupplierPriority.json';
        $priority = file_get_contents($filename);
        $priority = json_decode($priority, true);
        if (empty($priority)) {
            return fail('充值通道维护中');
        }
        $agent = Db::name('agent')
            ->field('balance')
            ->where('id', $agentId)
            ->find();
        $settlePrice = 0;

        // 代理商结算价：不同运营商，话费折扣不一样
        $config = Db::name('agent_service_config')
            ->field('discount_slow, discount_fast, discount_slow_all, discount_fast_all')
            ->where('agent_id', $agentId)
            ->where('serv_type', PRODUCT_MOBILE_SERV)
            ->find();
        if (empty($config)) {
            return fail('产品配置异常，请联系管理员。' . __LINE__);
        }
        $config['discount_slow_all'] = json_decode($config['discount_slow_all'], true);
        $config['discount_fast_all'] = json_decode($config['discount_fast_all'], true);

        // 代理商关联的业务员
        $salesmanId = AgentSalesman::getSalesmanIdByAgentId($agentId, PRODUCT_MOBILE_SERV);

        // 指定的供应商
        $usedSupplierIds = Db::name('agent_mobile_supplier')
            ->where('agent_id', $agentId)
            ->column('mobile_supplier_id');
        // 供应商信息
        // $supplierList = MobileSupplier::whereIn('id', $usedSupplierIds)->column('*', 'id');
        $supplierList = Db::name('mobile_supplier')
            ->whereIn('id', $usedSupplierIds)
            ->column('discount_slow, discount_fast, discount_slow_all, discount_fast_all', 'id');
        foreach ($supplierList as $k => $v) {
            $supplierList[$k]['discount_slow_all'] = json_decode($v['discount_slow_all'], true);
            $supplierList[$k]['discount_fast_all'] = json_decode($v['discount_fast_all'], true);
        }

        foreach ($data as $k => $v) {
            $index = $k + 1;
            if (empty($v['手机号码']) || empty($v['充值面额'])) {
                continue;
            }
            if (!checkMobile($v['手机号码'])) {
                return fail('第 ' . $index . ' 个订单手机号 ' . $v['手机号码'] . ' 格式有误');
            }
            if (!in_array($v['充值面额'], [30, 50, 100, 200])) {
                return fail('第 ' . $index . ' 个订单充值面额 ' . $v['充值面额'] . ' 有误。充值面额只能是 30/50/100/200');
            }
            $orderType = 1; // 1慢充 2快充
            if (empty($v['充值类型'])) {
                return fail('第 ' . $index . ' 个订单没有填写充值类型');
            }
            if (!in_array($v['充值类型'], ['快充', '慢充'])) {
                return fail('第' . $index . '个订单充值类型有误：' . $v['充值类型']);
            }
            if ('快充' == $v['充值类型']) {
                $orderType = 2;
            }

            $ispType = getMobileIsp($v['手机号码']);
            $fieldName = $map[$ispType];
            if (1 == $orderType) {
                $fieldName .= '_slow';
            } else {
                $fieldName .= '_fast';
            }

            if (empty($priority[$fieldName][$v['充值面额']])) {
                return fail('第' . $index . '个订单充值充值面额维护中');
            }
            $tmp = $priority[$fieldName][$v['充值面额']];
            // todo 待优化
            $supplier = [];
            foreach ($tmp as $id => $num) {
                if (!in_array($id, $usedSupplierIds)) {
                    continue;
                }
                $supplier = array_merge($supplier, array_fill(0, $num, $id));
            }
            if (empty($supplier)) {
                return fail('第' . $index . '个订单充值充值面额维护中。');
            }
            $max = count($supplier) - 1;
            $index = random_int(0, $max);

            $list[] = [
                'mobile' => $v['手机号码'],
                'amount' => $v['充值面额'],
                'order_type' => $orderType,
                'mobile_supplier_id' => $supplier[$index],
            ];
            unset($supplier);
            ++$orderNum;
            $orderAmount += $v['充值面额'];

            if (1 == $orderType) {
                // 慢充
                $settleDiscount = $config['discount_slow_all'][$ispType] ?? $config['discount_slow'];
            } else {
                // 快充
                $settleDiscount = $config['discount_fast_all'][$ispType] ?? $config['discount_fast'];
            }
            $settlePrice += intval(strval($v['充值面额'] * $settleDiscount));
        }
        if (empty($list)) {
            return fail('没有可导入的数据');
        }
        if ($orderNum > 1000) {
            return fail('单次最多导入 1000 个订单');
        }

        if ($settlePrice > $agent['balance']) {
            return fail('账户余额不足，请先充值。当前余额 ' . fen2yuan($agent['balance']) . ' 元');
        }

        $orderId = generateMobileOrderId();
        if (false === $orderId) {
            return fail('订单号生成失败，请稍后重试');
        }

        $orderNum = 0;
        $orderAmount = 0;
        foreach ($list as $k => $v) {
            $ispType = getMobileIsp($v['mobile']);
            Db::startTrans();
            try {
                if (1 == $v['order_type']) {
                    // 慢充
                    $settleDiscount = $config['discount_slow_all'][$ispType] ?? $config['discount_slow'];
                } else {
                    // 快充
                    $settleDiscount = $config['discount_fast_all'][$ispType] ?? $config['discount_fast'];
                }
                $settlePrice = intval(strval($v['amount'] * $settleDiscount));
                $balance = Db::name('agent')
                    ->where('id', $agentId)
                    ->lock(true)
                    ->value('balance');
                if ($balance < $settlePrice) {
                    Db::rollback();
                    throw new \Exception('账户余额不足：' . fen2yuan($balance));
                }

                // 供应商折扣相关计算
                if (2 == $v['order_type']) {
                    $supplierDiscount = $supplierList[$v['mobile_supplier_id']]['discount_fast_all'][$ispType] ?? $supplierList[$v['mobile_supplier_id']]['discount_fast'];
                } else {
                    $supplierDiscount = $supplierList[$v['mobile_supplier_id']]['discount_slow_all'][$ispType] ?? $supplierList[$v['mobile_supplier_id']]['discount_slow'];
                }
                $supplierPrice = intval(strval($v['amount'] * $supplierDiscount));

                $agentProfit = 0;
                $platformProfit = $settlePrice - $supplierPrice;

                $subOrderId = $orderId . sprintf('%04d', $k);
                $id = Db::name('mobile_order')
                    ->insertGetId([
                        'agent_id' => $agentId,
                        'order_id' => $orderId,
                        'sub_order_id' => $subOrderId,
                        'out_order_id' => $subOrderId,
                        'mobile' => $v['mobile'],
                        'amount' => yuan2fen($v['amount']),
                        'status' => 2,
                        'sale_discount' => $settleDiscount,
                        'settle_discount' => $settleDiscount,
                        'sale_price' => $settlePrice,
                        'settle_price' => $settlePrice,
                        'supplier_discount' => $supplierDiscount, //供应商折扣
                        'supplier_price' => $supplierPrice,
                        'platform_profit' => $platformProfit, // 平台利润
                        'profit' => $agentProfit,
                        'settle_type' => SETTLE_TYPE_PREPAY, // 预充
                        'order_type' => $v['order_type'],
                        'order_from' => ORDER_FROM_BATCH_IMPORT,
                        'mobile_supplier_id' => $v['mobile_supplier_id'],
                        'salesman_id' => $salesmanId,
                    ]);
                $res = Db::name('agent')
                    ->where('id', $agentId)
                    ->where('balance', '>=', $settlePrice)
                    ->dec('balance', $settlePrice)
                    ->update([
                        'balance_last_updated_at' => date('Y-m-d H:i:s'),
                    ]);
                if (!$res) {
                    Db::rollback();

                    throw new \Exception('账户余额不足' . __LINE__);
                }

                Db::name('agent_balance_log')
                    ->insert([
                        'agent_id' => $agentId,
                        'type' => BALANCE_MOBILE_RECHARGE,
                        'amount' => -$settlePrice,
                        'old_balance' => $balance,
                        'new_balance' => $balance - $settlePrice,
                        'remark' => '话费充值：' . $v['amount'] . '元，结算价：' . fen2yuan($settlePrice) . '元。订单号：' . $subOrderId,
                        'quote_id' => $id,
                        'trade_no' => $subOrderId,
                    ]);

                $orderAmount += $v['amount'];

                ++$orderNum;

                Db::commit();
            } catch (\Exception $e) {
                Db::rollback();

                if ($orderNum) {
                    return success('成功导入 ' . $orderNum . ' 个订单，充值总额 ' . $orderAmount . ' 元。导入失败：' . $e->getMessage());
                } else {
                    return fail('导入失败：' . $e->getMessage());
                }
            }
        }

        return success('成功导入 ' . $orderNum . ' 个订单，充值总额 ' . $orderAmount . ' 元');
    }

    /**
     * API 订单手动回调.
     * 测试环境手动回调
     */
    public function manualNotify($params)
    {
        if (empty($params['id']) && empty($params['order_id'])) {
            $this->error = '参数有误';

            return false;
        }
        if (empty($params['status']) || !in_array($params['status'], [3, 4])) {
            $this->error = '回调状态有误';

            return false;
        }

        $order = Db::name('mobile_order')
            ->where('id', $params['id'])
            ->where('agent_id', $params['agent_id'])
            ->find();
        if (empty($order)) {
            $this->error = '订单不存在';

            return false;
        }
        if ($order['order_from'] != ORDER_FROM_API) {
            $this->error = '该订单不是 API 接口订单，无法回调';

            return false;
        }
        if (empty($order['notify_url'])) {
            $this->error = '该订单没有设置回调地址，无法回调';

            return false;
        }
        $agent = Db::name('agent')
            ->field('app_key, app_secret')
            ->where('id', $order['agent_id'])
            ->find();

        $notifyData = [
            'timestamp' => time(),
            'order_id' => strval($order['order_id']),
            'out_order_id' => $order['out_order_id'],
            'status' => $params['status'],
            'mobile' => $order['mobile'],
            'amount' => fen2yuan($order['amount']),
            'app_key' => $agent['app_key'],
            'official_sn' => $order['official_sn'] ?? '',
        ];
        $notifyData['sign'] = getSign($notifyData, $agent['app_secret']);
        $notifyData = json_encode($notifyData);
        $res = curlPost($order['notify_url'], $notifyData, [
            'Content-type: application/json;charset=utf-8',
        ]);

        return [
            'data' => $notifyData,
            'result' => $res,
        ];

        // if ($res === 'SUCCESS' || $res === 'ok') {
        //     return true;
        // }

        // $this->error = '通知失败：' . $res;

        // return false;
    }

    public function getError()
    {
        return $this->error;
    }
}
